package br.com.sig.financeiro.despesa.presentation.action;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.enterprise.event.ObserverException;
import javax.faces.bean.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;

import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.joda.time.LocalDate;

import br.com.sig.criteria.CriteriaVisitor;
import br.com.sig.financeiro.despesa.business.event.PagarDespesaEvent;
import br.com.sig.financeiro.despesa.business.model.bo.DespesaBO;
import br.com.sig.financeiro.despesa.business.model.entity.Despesa;
import br.com.sig.financeiro.despesa.business.model.entity.DespesaFixa;
import br.com.sig.financeiro.despesa.business.model.entity.DespesaFlutuante;
import br.com.sig.financeiro.despesa.business.model.enumeration.TipoDeDespesa;
import br.com.sig.presentation.action.BaseListAction;
import br.com.sig.security.BaseIdentity;
import br.com.sig.security.Identity;

@Named
@ViewScoped
public class DespesaList extends BaseListAction<Despesa> {
	
	private static final long serialVersionUID = -5833933781455640516L;
	
	private Date dataDeInicio = null;
	private Date dataDeTermino = null;
	private Date dataDePagamentoInicio = null;
	private Date dataDePagamentoTermino = null;
	private Date dataDePagamento = null;
	
	private TipoDeDespesa tipoDeDespesa;
	
	@Inject
	@Identity
	private BaseIdentity identity;	
	
	@Inject
	private DespesaBO despesaBO;

	@PostConstruct
	public void init() {
		setService(despesaBO);
		setSortField("vencimento");
	}
	
	@Override
	protected void clearInstance() {
		super.clearInstance();
		this.tipoDeDespesa = null;
	}	
	
	@Override
	public void find() {
		this.visitor = new CriteriaVisitor() {
			
			@Override
			public void visit(Criteria criteria) {
				if (dataDeInicio != null) {
					criteria.add(Restrictions.ge("vencimento", dataDeInicio));
				}
				
				if (dataDeTermino != null) {
					criteria.add(Restrictions.le("vencimento", dataDeTermino));
				}
				
				if (dataDePagamentoInicio != null) {
					criteria.add(Restrictions.ge("dataDePagamento", dataDePagamentoInicio));
				}
				
				if (dataDePagamentoTermino != null) {
					criteria.add(Restrictions.le("dataDePagamento", dataDePagamentoTermino));
				}				
			}
		};
		
		super.find();
	}
	
	@Override
	protected Despesa createInstance() {
		this.dataDeInicio = null;
		this.dataDeTermino = null;
		return super.createInstance();
	}
	
	@Override
	public String rowStyleClass(Despesa despesa) {
		LocalDate vencimento = new LocalDate(despesa.getVencimento().getTime());
		if (despesa.getDataDePagamento() == null && vencimento.compareTo(new LocalDate()) < 0) {
			return "despesaVencida";
		} else {
			return null;
		}
	}
	
	public boolean enablePayment() {
		
		for (Despesa despesa : getSelections()) {
			if (despesa.getDataDePagamento() != null) {
				return false;
			}
		}
		
		if (identity.hasPermission("sig.financeiro.despesa.escrita.pagamento") &&
				getSelectedItem() != null && getSelectedItem().getDataDePagamento() == null) {
			return true;
		}
		return false;
	}
	
	public void pagar() {
		
		try {
			beanManager.fireEvent(new PagarDespesaEvent(getDataDePagamento(), new ArrayList<Despesa>(getSelections())));
			clearSelections();
			setSelectedItem(null);
			messages.info("Pagamento efetuado com sucesso.");			
		} catch (ObserverException e) {			
			messages.error("Falha ao processar o pagamento. Contacte o Administrador do Sistema.");
		} finally {
			setDataDePagamento(null);
		}
		
	}	
	
	public Date getDataDeInicio() {
		return dataDeInicio;
	}

	public void setDataDeInicio(Date dataDeInicio) {
		this.dataDeInicio = dataDeInicio;
	}

	public Date getDataDeTermino() {
		return dataDeTermino;
	}

	public void setDataDeTermino(Date dataDeTermino) {
		this.dataDeTermino = dataDeTermino;
	}

	public Date getDataDePagamentoInicio() {
		return dataDePagamentoInicio;
	}

	public void setDataDePagamentoInicio(Date dataDePagamentoInicio) {
		this.dataDePagamentoInicio = dataDePagamentoInicio;
	}

	public Date getDataDePagamentoTermino() {
		return dataDePagamentoTermino;
	}

	public void setDataDePagamentoTermino(Date dataDePagamentoTermino) {
		this.dataDePagamentoTermino = dataDePagamentoTermino;
	}

	public TipoDeDespesa getTipoDeDespesa() {
		return tipoDeDespesa;
	}	
	
	public void setTipoDeDespesa(TipoDeDespesa tipoDeDespesa) {		
		if (tipoDeDespesa == null) {
			return;
		}
		
		this.tipoDeDespesa = tipoDeDespesa;
		
		if (TipoDeDespesa.FIXA.equals(this.tipoDeDespesa)) {
			setInstance(new DespesaFixa());
		} else {
			setInstance(new DespesaFlutuante());
		}
	}
	
	public Date getDataDePagamento() {
		return dataDePagamento;
	}

	public void setDataDePagamento(Date dataDePagamento) {
		this.dataDePagamento = dataDePagamento;
	}	
	
	public BigDecimal getTotalDespesaFixa() {
		BigDecimal total = new BigDecimal(0);
		
		for (Despesa despesa : (List<Despesa>)getPagedResult().getWrappedData()) {
			if (despesa.getValor() != null && despesa.isDespesaFixa()) {
				total = total.add(despesa.getValor());
			}
		}
		
		return total;
	}
	
	public BigDecimal getTotalDespesaFlutuante() {
		BigDecimal total = new BigDecimal(0);
		
		for (Despesa despesa : (List<Despesa>)getPagedResult().getWrappedData()) {
			if (despesa.getValor() != null && despesa.isDespesaFlutuante()) {
				total = total.add(despesa.getValor());
			}
		}
		
		return total;
	}
	
	public BigDecimal getTotalGeral() {
		return getTotalDespesaFixa().add(getTotalDespesaFlutuante());
	}
}